package main

import (
	"fmt"
	"net"
	"strings"
	"time"
)

type Client struct {
	C    chan string
	Name string
	Addr string
}

var onlineUserName map[string]Client = make(map[string]Client)

var message = make(chan string)

func main() {
	server, err := net.Listen("tcp", ":8080")
	if err != nil {
		fmt.Println("net listen err :", err.Error())
		return
	}
	defer server.Close()
	go Manager()
	for {
		conn, err2 := server.Accept()
		if err2 != nil {
			fmt.Println("server accept error", err2.Error())
			continue
		}
		go HandleConn(conn) //处理用户连接
	}

}

func WriteMsgToClient(conn net.Conn, client Client) {
	for msg := range client.C {
		conn.Write([]byte(msg + "\n"))
	}
}

func MakeMsg(client Client, msg string) string {
	return "[ " + client.Addr + " ] " + client.Name + " " + msg
}

func RevMessage(conn net.Conn, client Client, isQuit chan bool, hasData chan bool) {
	buf := make([]byte, 2048)
	for {
		n, err := conn.Read(buf)
		if n == 0 {
			isQuit <- true
			fmt.Println("conn.Read ", err.Error())
			return
		}

		msg := string(buf[:n])

		if len(msg) == 3 && msg == "who" {
			conn.Write([]byte("user list: \n"))
			for _, userInfo := range onlineUserName {
				onlineInfo := userInfo.Addr + " : " + userInfo.Name + "\n"
				conn.Write([]byte(onlineInfo))
			}
		} else if len(msg) >= 8 && msg[:7] == "rename" {
			name := strings.Split(msg, "|")[1]
			client.Name = name
		} else {
			message <- MakeMsg(client, msg)
		}

		hasData <- true
	}
}

func HandleConn(conn net.Conn) {
	defer conn.Close()
	cliAddr := conn.RemoteAddr().String()
	client := Client{make(chan string), cliAddr, cliAddr}
	onlineUserName[cliAddr] = client
	go WriteMsgToClient(conn, client)

	//广播用户上线
	message <- MakeMsg(client, "login")

	client.C <- "i am here~~~~"

	isQuit := make(chan bool)  //是否退出
	hasData := make(chan bool) //是否超时

	go RevMessage(conn, client, isQuit, hasData)

	for {
		//通过select检测退出
		select {
		case <-isQuit:
			delete(onlineUserName, cliAddr)
			message <- MakeMsg(client, "logout")
			return
		case <-hasData:
		case <-time.After(time.Second * 10):
			delete(onlineUserName, cliAddr)
			message <- MakeMsg(client, "timeout")
			return
		}
	}
}

// 处理消息
func Manager() {
	for {
		msg := <-message
		for _, cli := range onlineUserName {
			cli.C <- msg
		}
	}
}
